const net = require('net');
const WebSocket = require('ws');
const ejs = require('ejs');
const dayjs = require('dayjs');
const utils = require('./src/utils');
const SQLServerDB = require('./src/db');

const PORT = 1021;
const HOST = '0.0.0.0';

const getClientName = (socket) => {
  const ip = socket.remoteAddress;
  const port = socket.remotePort;
  return `client:${ip}:${port}`;
}

const db = new SQLServerDB();

module.exports = function () {
 

  // web监控客户端
  const clientWSList = [];
  //  socket存储
  const socketClients = {};

  const that = this;

  this.addClient = function (client) {
    clientWSList.push(client);
  }

  this.removeClient = function (clientId) {
    const index = clientWSList.find(i => i.clientId === clientId);
    if (index > -1) {
      clientWSList.splice(index, 1);
    }
  }

  // this.writeData = function (socket, data) {
  //   if (socketClients[mac]) {
  //     if (socketClients[dist].readyState === 'open') {
  //       socketClients[dist].write(utils.str2ArrayBuffer(data), function () {
  //         console.log(`send data to ${dist} ${data} success`)
  //       });
  //     }
  //   }
  // }

  // 通过socket写入数据
  this.writeData = function(socket, value) {
    socket.write(utils.str2ArrayBuffer(value), function () {
      // console.log(`send data to ${getClientName(socket)} ${value} success`)
    });
  }

  // 通过mac写入数据
  this.writeDataByMac = function(mac, value) {
    return new Promise(function(resolve, reject) {
      if (socketClients[mac]) {
        const socket = socketClients[mac].socket;
        console.log(`write mac ${mac} value ${value}`);
        if (socket.readyState === 'open') {
          socket.resolve = resolve;
          socket.write(utils.str2ArrayBuffer(value), function () {
            // console.log(`send data to ${getClientName(socket)} ${value} success`)
          });
          setTimeout(() => {
            reject('发送回复超时');
          }, 5000)
        } else {
          reject('设备不在线');
        }
      } else {
        reject('检测不到设备');
      }
    })
  }

  const sendMessageToWebClient = (socket, type, msg) => {
    clientWSList.forEach(({ws}) => {
      ws.remoteAddress = socket.remoteAddress;
      ws.remotePort = socket.remotePort;
      const template = ejs.compile(msg);
      if (ws.readyState == WebSocket.OPEN) {
        ws.send(JSON.stringify({
          type: type,
          msg: template({ ws: ws }),
        }))
      }
    })
  }

  const clientHandle = function (socket) {

    socket.setTimeout(30000, () => {
      // 30s超时
      socket.end();
      sendMessageToWebClient(socket, 'error',  `mac ${socket.mac} socket timeout!`);
    })

    socket.on('data', function (data) {
      // console.log('web client length is ', clientWSList.length, 'online client mac is ', Object.keys(socketClients));
      const receiveStr = utils.bytes2Str(data);
      sendMessageToWebClient(socket, 'onlineDevice', Object.keys(socketClients).join(','));
      sendMessageToWebClient(socket, 'realtime', `${dayjs().format('YYYY-MM-DD HH:mm:ss')} ${socket.mac}: ${receiveStr}`);
      if (receiveStr === ('4f:4b:1a')) {
        if (typeof socket.resolve === 'function') {
          socket.resolve();
          socket.resolve = null;
        }
      }
      if (receiveStr.indexOf('7b:00:08:a2:02') > -1) {
        // mac地址类型
        const mac = receiveStr.split(':').slice(5, 11).map(i => i.toUpperCase()).join("");
        socket.mac = mac;
        socketClients[mac] = {
          socket: socket,
          remoteAddress: socket.remoteAddress,
          remotePort: socket.remotePort,
          mac: mac,
          connectedTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
        };
        db.getRequest().then(sqlReq => {
          sqlReq.query(`update t_device set IsConnect=1 where MAC='${mac}'`).then(updateRet => {
            // console.log(updateRet);
          })
        })
        // that.writeData(socket, "7B0002A201A57D");
        sendMessageToWebClient(socket, 'connected', `ip is ${socket.remoteAddress}:${socket.remotePort} and mac is ${mac} connected `);
      }
      if (receiveStr.indexOf('7b:00:16:a2:01') > -1) {
        // 获取经纬度的
        const ret = utils.parseLatLng(receiveStr);
        console.log(ret, receiveStr);
        if (ret && socket.mac) {
          db.getRequest().then(sqlReq => {
            console.log(`update t_device set Lat='${ret[0]}', Lng='${ret[1]}' where MAC='${socket.mac}'`);
            sqlReq.query(`update t_device set Lat='${ret[0]}', Lng='${ret[1]}' where MAC='${socket.mac}'`).then(updateRet => {})
          })
        }
      }
      if (receiveStr.indexOf("7b:00:02:a4:01:a7:7d:1a") > -1) {
        // new connect
        that.writeData(socket, "7B0002A202A67D");
      }
    });

    socket.on('close', function () {
      delete socketClients[socket.mac];
      if (socket.mac) {
        db.getRequest().then(sqlReq => {
          sqlReq.query(`update t_device set IsConnect=0 where MAC='${socket.mac}'`).then(updateRet => {})
        })
        sendMessageToWebClient(socket, 'close', `client <%= ws.remoteAddress %>:<%= ws.remotePort %> closed`);
        socket.end();
      }
    });

    socket.on('error', function (err) {
      sendMessageToWebClient(socket, 'error', `server error on <%= ws.remoteAddress %>:<%= ws.remotePort %> is ${err}`);
      socket.end();
    })

    socket.on('timeout', function (err) {
      sendMessageToWebClient(socket, 'error', `socket timeout on <%= ws.remoteAddress %>:<%= ws.remotePort %> is ${err}`);
      socket.end();
    })
  }

  const app = net.createServer(clientHandle);
  app.listen({
    port: PORT,
    host: HOST
  }, function () {
    console.log('tcp is listening on port ' + PORT);
    setInterval(() => {
      for (let key in socketClients) {
        const client = socketClients[key];
        if (client.connectedTime) {
          if (Math.abs(dayjs(client.connectedTime).diff(dayjs(), 's')) > 60) {
            // 10分钟内没有生效
            if (client.socket.mac) {
              db.getRequest().then(sqlReq => {
                sqlReq.query(`update t_device set IsConnect=0 where MAC='${client.mac}'`).then(() => {})
              })
              sendMessageToWebClient(client.socket, 'close', `client closed mac is ${client.mac} timeout 60s`);
              sendMessageToWebClient(client.socket, 'onlineDevice', Object.keys(socketClients).join(','))
              client.socket.end();
            }
            delete socketClients[key];
          }
        }
      }
    }, 4000);
  })

};
